package com.itheima.project.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.itheima.project.anno.EsField;
import com.itheima.project.anno.EsId;
import com.itheima.project.anno.EsIndex;
import com.itheima.project.constant.search.SearchConstants;
import com.itheima.project.core.enums.search.SearchEnum;
import com.itheima.project.exception.ProjectException;
import com.itheima.project.service.IndexService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.lang.reflect.Field;

/**
 */
@Service
@Slf4j
public class IndexServiceImpl implements IndexService {
    @Autowired
    private RestHighLevelClient client;
    @Override
    public void createIndex(Class<?> tclass) {
        // 索引库名称
        String indexName = getIndexName(tclass);
        // 拼接所有请求参数
        JSONObject sourceJson = new JSONObject();
        // TODO 封装setting信息
        // 封装映射信息
        JSONObject mappings = new JSONObject();
        // 映射属性信息
        JSONObject properties = new JSONObject();
        // 获取所有声明的属性
        Field[] declaredFields = tclass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            JSONObject fieldJson = new JSONObject();
            // 获取每个属性上的EsField注解
            EsField esField = declaredField.getAnnotation(EsField.class);
            if(esField!=null){
                // 基于esField字段配置映射属性
                boolean index = esField.isIndex();
                String analyzer = esField.analyzer();
                EsField.FieldType type = esField.type();
                fieldJson.put(SearchConstants.FIELD_MAPPING_TYPE, type.getType());
                fieldJson.put(SearchConstants.FIELD_MAPPING_INDEX, index);
                if (StringUtils.isNotBlank(analyzer)) {
                    fieldJson.put(SearchConstants.FIELD_MAPPING_ANALYZE,analyzer);
                }
            }
            // 如果标记了EsId字段  类型直接设置为keyword类型
            EsId esId = declaredField.getAnnotation(EsId.class);
            if(esId != null){
                fieldJson.put(SearchConstants.FIELD_MAPPING_TYPE, EsField.FieldType.KEYWORD.getType());
            }
            properties.put(declaredField.getName(),fieldJson);
        }
        // 将上面内容拼接成json   复用createIndex方法
        mappings.put(SearchConstants.INDEX_MAPPINGS_PROPERTIES,properties);
        sourceJson.put(SearchConstants.INDEX_MAPPINGS,mappings);
        createIndex(sourceJson.toJSONString(),indexName);
    }
    @Override
    public void createIndex(String source, String indexName) {
        log.debug(" == 创建索引库开始 == 索引库名称: {}    请求参数: {}",source,indexName);
        try {
            CreateIndexRequest request = new CreateIndexRequest(indexName);
            request.source(source, XContentType.JSON);
            CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
            if(!response.isAcknowledged()){
                log.error("创建索引库失败 , 返回结果详细信息: {}",response);
                throw new ProjectException(SearchEnum.INDEX_CREATE_FAIL);
            }
            log.info(" == 索引库成功创建    名称:{}  ==",indexName );
        } catch (Exception e) {
            e.printStackTrace();
            log.error("创建索引库失败 异常原因: {}",e.getMessage());
            throw new ProjectException(SearchEnum.INDEX_CREATE_FAIL);
        }
    }
    @Override
    public boolean existIndex(Class<?> tclass) {
        return existIndex(getIndexName(tclass));
    }
    @Override
    public boolean existIndex(String indexName) {
        GetIndexRequest request = new GetIndexRequest(indexName);
        try {
            return client.indices().exists(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("查询是否包含失败， 索引库名称:{}  错误原因:{}",indexName,e.getMessage());
            throw new ProjectException(SearchEnum.INDEX_GET_FAIL);
        }
    }
    @Override
    public void deleteIndex(String indexName) {
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        try {
            client.indices().delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("删除索引库失败， 索引库名称:{}  错误原因:{}",indexName,e.getMessage());
            throw new ProjectException(SearchEnum.INDEX_DELETE_FAIL);
        }
    }
    @Override
    public void deleteIndex(Class<?> tclass) {
        deleteIndex(getIndexName(tclass));
    }
    private String getIndexName(Class<?> c){
        EsIndex annotation = c.getAnnotation(EsIndex.class);
        if (annotation == null){
            throw new ProjectException(SearchEnum.FAIL.getCode(),"获取索引库名称失败，未发现@EsIndex注解");
        }
        // 索引库名称
        return annotation.indexName();
    }
}
